I like to use YUI’s Compressor tool for minifying my javascripts. It’s brilliant. However my javascript API is becoming rather large and complex, and I wanted to use debugging facilities like printing log messages and littering my code with assertions as much as I need to, without worrying about removing them manually for the release version of the scripts. I didn’t find anything on the net that really supported what I wanted. So I wrote my own solution.
Presenting to you the “YUI Compressor extended” tool. It now has an extra option: --exclude-namespace namespaces
. Where “namespaces” is a semi-colon separated list of global namespaces to be entirely removed from your javascript. That is, the declarations and usage of the global namespace.
What constitutes a “global namespace”?
Essentially, any global object. Here is a practical example to illustrate its intention where a global namespace called “debug” is declared:
/** * The debug namespace will be removed in release builds */ debug = {}; debug.assert = function(cond, msg) { if (!cond) { throw new Error("Assertion failed" + (msg ? ": " + msg : "")); } } /** * Use this to run debug-version only code. * In the build, the code will be entirly removed since the debug namespace is excluded. */ debug.exec = function(func) { func(); } debug.print = function(msg) { if (console && console.log) { console.log(msg); } else { // Here you might actually do something more realistic, like your own debug pane in a floating DIV. alert(msg); } } debug.println = function(msg) { debug.print(msg + "\n"); }
So debug is just a global object – intended to be a namespace. Now lets look at how your scripts might use it:
PrintDOMAction = function(startNode, startIndex, endNode, endIndex) { debug.assert( !(startNode.nodeName == "#text" && (startIndex >= startNode.nodeValue.length)), "Start index out of range" ); debug.assert( !(endNode.nodeName == "#text" && (endIndex >= endNode.nodeValue.length)), "End index out of range" ); debug.assert( !(startNode.nodeName == "#text" && startNode == endNode && startIndex > endIndex), "Invalid range" ); // Set members this.startNodeRef = startNode; this.startingIndex = startIndex; this.endNodeRef = endNode; this.endingIndex = endIndex; }
Here PrintDOMAction
is a constructor function. This is an example of checking arguments with assertions.
Now when you use the extended YUI compressor with –exlude-namespace “debug” as an option, all the debug declarations will vanish and the PrintDOMAction constructor function will look like:
PrintDOMAction = function(startNode, startIndex, endNode, endIndex) { // Set members this.startNodeRef = startNode; this.startingIndex = startIndex; this.endNodeRef = endNode; this.endingIndex = endIndex; }
(Assuming all whitespaces/newlines are preserved and munging is disabled so that it is not compressed).
Here’s a neat idea that may be helpful: to run could only in “debug mode” using the simple debug namespace presented above you would write:
... debug.exec(function() { // You can have anything in this anonymous function and it will only be included in debug mode! var specialButton = document.createElement("input"); specialButton.type = "button"; specialButton.onclick = function() { alert("you clicked a special function, exclusively available to debug mode!"); } document.body.appendChild(specialButton); }); ...
Usage
I have a bunch of perl/bash scripts that glue all my javascripts together (in the correct dependancy order), which then compresses the final large script using the YUI Compressor extended tool:
java -jar yuicompressor-ext-2.4.2.1.jar -x "debug" combinedapi.js > /build/myapi-release.js
The “-x” option is a shorthand for “–exclude-namespace”. This removes the global namespace named “debug”. “combinedapi.js” is the file I’m compressing. And i’m redirecting standard out to a fresh new file called “/build/myapi-release.js” (or you could just use the -o option). NOTE: This command line syntax might differ on windows.
Download source and packaged binary (bytecode)
- yuicompressor-ext-2.4.2.1.tar.gz – released 9th May 2009.
The extended version of the YUI compressor is licensed under the Mozilla Public License (MPL)
If you have any questions/issues/comments about the extended YUI compressor add a comment to this post.
I am the (new) maintainer of YUICompressor, and would love to fold this into YUICompressor by default. Any interest in sharing your code?
I am sorry of lost this code, probably back in my home country on a dust collected CD 😦